package service

import (
	"context"
	"github.com/spf13/viper"
	"go-shop-api/internal/dao"
	"go-shop-api/pkg/e"
	"go-shop-api/pkg/funs"
	"go-shop-api/pkg/serializer"
	"go-shop-api/pkg/zydhjwt"
	"go-shop-api/pkg/zydhlog"
	"gopkg.in/mail.v2"
	"strings"
)

// SendEmailService 发送邮件
type SendEmailService struct {
	Email string `json:"email" form:"email" binding:"email"`
	Pwd   string `json:"pwd" form:"pwd"`
	//场景 1 绑定邮箱 2 修改密码 3.邮箱验证码登陆 4 解绑邮箱 10 解绑
	Scene uint `json:"scene" form:"scene"`
}

// ValidEmailService 验证邮箱
type ValidEmailService struct {
	Token string `json:"token" form:"token" binding:"token"`
}

var (
	BindingEmail        = 1
	RelieveBindingEmail = 4
	UpdateEmail         = 2
	VailEmail           = 3
)

var EmailTemplate = map[int]string{
	BindingEmail:        "您正在绑定邮箱Email",
	RelieveBindingEmail: "您正在解除绑定邮箱Email",
	UpdateEmail:         "您正在修改密码Email",
	VailEmail:           "您正在验证邮箱Email",
}

func (ss *SendEmailService) SendEmail(ctx context.Context, uid uint) *serializer.Response {

	//生成token
	token, err := zydhjwt.GenerateEmailToken(uid, ss.Email, ss.Pwd, ss.Scene)
	if err != nil {
		return serializer.NewResponse(e.ErrorAuthToken, err.Error(), e.TipsGeneral, nil)
	}
	//获取需要发送的邮件模板
	notice, ok := EmailTemplate[int(ss.Scene)]
	if !ok {
		return serializer.NewResponse(e.ErrorEmailScene, e.TipsNil, e.TipsGeneral, nil)
	}

	////发送方
	//address := viper.Get("email.valid_email").(string) + token
	////替换字符串
	//mailTxt := strings.Replace(notice, "Email", address, -1)
	//m := mail.NewMessage()
	//m.SetHeader("From", viper.Get("email.smtp_email").(string)) //发送方
	//m.SetHeader("To", ss.Email)                                 //接收方
	//m.SetHeader("Subject", "朝游东海")                          //主体
	//m.SetBody("text/html", mailTxt)
	//d := mail.NewDialer(viper.Get("email.smtp_host").(string), 465, viper.GetString("email.smtp_email"), viper.GetString("email.smtp_pass"))
	//d.StartTLSPolicy = mail.OpportunisticStartTLS
	//if err = d.DialAndSend(m); err != nil {
	//	return serializer.NewResponse(e.ErrorSentEmail, err.Error(), e.TipsGeneral, nil)
	//}

	//以上都可以直接用 go 协程
	go sendEmail(token, notice, ss.Email)
	//go writeSendEmailLog()  -- 写日志

	return serializer.NewResponse(e.Success, e.TipsOk, e.TipsSuccessSendEmail, nil)
}

func sendEmail(token, notice, toEmail string) {
	//发送方
	address := viper.Get("email.valid_email").(string) + token
	//替换字符串
	mailTxt := strings.Replace(notice, "Email", address, -1)
	m := mail.NewMessage()
	m.SetHeader("From", viper.Get("email.smtp_email").(string)) //发送方
	m.SetHeader("To", toEmail)                                  //接收方
	m.SetHeader("Subject", "朝游东海")                              //主体
	m.SetBody("text/html", mailTxt)
	d := mail.NewDialer(viper.Get("email.smtp_host").(string), 465, viper.GetString("email.smtp_email"), viper.GetString("email.smtp_pass"))
	d.StartTLSPolicy = mail.OpportunisticStartTLS
	if err := d.DialAndSend(m); err != nil {
		zydhlog.Error(err.Error())
		//return serializer.NewResponse(e.ErrorSentEmail, err.Error(), e.TipsGeneral, nil)
	}
}

// ValidEmail 验证邮箱
func (s *ValidEmailService) ValidEmail(ctx context.Context, token string) *serializer.Response {

	s.Token = token

	if s.Token == "" {
		return serializer.NewResponse(e.ErrorTokenIsNil, e.TipsErrorTokenIsNil, e.TipsErrorTokenIsNil, nil)
	}
	claims, err := zydhjwt.ParseEmailToken(s.Token)
	if err != nil {
		return serializer.NewResponse(e.ErrorInvalidToken, err.Error(), e.TipsErrorInvalidToken, nil)
	}
	//获取用户的信息
	userDao := dao.NewUserDao(ctx)
	user, err := userDao.GetUserByUid(claims.UserID)
	if err != nil {
		return serializer.NewResponse(e.ErrorExistUserNotFind, err.Error(), e.TipsErrorInvalidToken, nil)
	}
	//根据场景，不同方法
	switch int(claims.Scene) {
	case BindingEmail:
		//绑定邮箱
		user.Email = claims.Email
	case RelieveBindingEmail:
		//解除绑定邮箱
		user.Email = ""
	case UpdateEmail:
		//修改密码

		//密码加密 前端传过来的也是密文，需要对其解密，此处无
		password, err := funs.BcryptPwd(claims.Password, 12)
		if err != nil {
			zydhlog.Error(err.Error())
			return serializer.NewResponse(e.ErrorFailEncrypt, err.Error(), e.TipsGeneral, nil)
		}
		user.Password = password
	}

	//更新用户
	if err = userDao.UpdateUserById(user.ID, user); err != nil {
		zydhlog.Error(err.Error())
		return serializer.NewResponse(e.Error, err.Error(), e.TipsGeneral, nil)
	}
	return serializer.NewResponse(e.Success, e.TipsOk, e.TipsSuccessOperate, nil)
}
